package logic;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.InputMismatchException;
import java.util.Vector;

import utility.InputEmptyException;
import utility.InputInvalidException;
import utility.UserInput;

public class Parser {

	private static final String SHORTFORM_BOTH_DATE = "bd";
	private static final String SHORTFORM_END_DATE = "ed";
	private static final String SHORTFORM_START_DATE = "sd";
	private static final String SHORTFORM_BOTH_TIME = "bt";
	private static final String SHORTFORM_END_TIME = "et";
	private static final String SHORTFORM_START_TIME = "st";
	private static final String DASH = "-";
	private static final String ERROR_MESSAGE_INVALID_COMMAND = "Command Word Invalid";
	private static final String ERROR_MESSAGE_NO_PARAMETERS = "Please enter the parameters.";
	private static final String ERROR_MESSAGE_DISPLAY_RANGE = "Display range must have only 2 dates.";
	private static final String TASK_END_INDICATOR = ">";
	private static final String TASK_START_INDICATOR = "<";
	private static final int INDEX_BOTH_TIME = 5;
	private static final int INDEX_START_TIME = 3;
	private static final int INDEX_END_TIME = 4;
	private static final int OFFSET_FOR_BD_BT = 2;
	private static final int INDEX_END_DATE = 1;
	private static final int OFFSET_FOR_SD_ST_ED_ET = 1;
	private static final int INDEX_BOTH_DATE = 2;
	private static final int INDEX_START_DATE = 0;
	private static final String ERROR_MESSAGE_WRONG_ED = "End Date must be valid.";
	private static final String ERROR_MESSAGE_NO_ED = "End Date is missing.";
	private static final String ERROR_MESSAGE_WRONG_SD = "Start Date must be valid.";
	private static final String ERROR_MESSAGE_NO_SD = "Start Date is missing.";
	private static final String ERROR_MESSAGE_WRONG_ET = "End Time must be valid.";
	private static final String ERROR_MESSAGE_NO_ET = "End Time is missing.";
	private static final String ERROR_MESSAGE_WRONG_ST = "Start Time must be valid.";
	private static final String ERROR_MESSAGE_NO_ST = "Start Time is missing.";
	private static final int FIRST_INDEX = 0;
	private static final int INDEX_NOT_FOUND = -1;
	private static final String ERROR_MESSAGE_EDIT_NO_PARAMETERS = "Edit must have parameters.";
	private static final String ERROR_MESSAGE_EDIT_INVALID_ROW = "Edit must have valid row number.";
	private static final String ERROR_MESSAGE_DISPLAY = "Display Type must be correct.";
	private static final String ERROR_MESSAGE_DELETE = "Delete must have valid row number.";
	private static final String STANDARDISED_TIME_FORMAT = "HHmm";
	private static final String STANDARDISED_DATE_FORMAT = "dd/MM/yy";
	private static final String ERROR_MESSAGE_UNDONE = "unDone must have valid row number.";
	private static final String ERROR_MESSAGE_DONE = "Done must have valid row number.";
	private static final int START_INDEX = 0;
	private static final String EMPTY_STRING = "";
	private static final String COMMAND_SRC = "src";
	private static final String COMMAND_SEARCH = "search";
	private static final String COMMAND_UND = "und";
	private static final String COMMAND_UNDO = "undo";
	private static final String COMMAND_RED = "red";
	private static final String COMMAND_REDO = "redo";
	private static final String COMMAND_EDI = "edi";
	private static final String COMMAND_EDIT = "edit";
	private static final String COMMAND_DIS = "dis";
	private static final String COMMAND_DISPLAY = "display";
	private static final String COMMAND_DEL = "del";
	private static final String COMMAND_DELETE = "delete";
	private static final String COMMAND_ADD = "add";
	private static final String COMMAND_DONE = "done";
	private static final String COMMAND_UNDONE = "undone";

	private static final int EDIT_ROW = 0;
	private static final int DISPLAY_TYPE = 0;
	private static final String DISPLAY_RANGE = "r";
	private static final String DISPLAY_ALL = "a";
	private static final String DISPLAY_ALL_FLOATING = "f";

	private static final String WHITESPACE = " ";
	private static final int FIRST_WORD = 0;
	private static final String COMMAND_EXIT = "exit";
	private static final int FIRST_DATE = 1;
	private static final int SECOND_DATE = 2;

	public static UserInput validate(String input) throws InputEmptyException,
			InputMismatchException, ParseException, InputInvalidException {
		UserInput ui = new UserInput();
		if (input.isEmpty()) {
			throw new InputEmptyException(EMPTY_STRING);
		}
		String firstWord = getFirstWord(input);
		input = removeFirstWord(firstWord, input);
		if (isCommandWord(firstWord)) {
			ui.command = firstWord.toLowerCase();
			return checkParameters(firstWord, input, ui);
		} else {
			assert !isCommandWord(firstWord) : firstWord;
			throw new InputMismatchException(ERROR_MESSAGE_INVALID_COMMAND);
		}
	}

	private static String removeFirstWord(String firstWord, String input) {
		return input.replaceFirst(firstWord, EMPTY_STRING);
	}

	private static String getFirstWord(String input) {
		return input.split(WHITESPACE)[FIRST_WORD];
	}

	private static boolean isCommandWord(String firstWord) {
		switch (firstWord.toLowerCase()) {
		case COMMAND_ADD:
		case COMMAND_DELETE:
		case COMMAND_DEL:
		case COMMAND_DISPLAY:
		case COMMAND_DIS:
		case COMMAND_EDIT:
		case COMMAND_EDI:
		case COMMAND_UNDO:
		case COMMAND_UND:
		case COMMAND_SEARCH:
		case COMMAND_SRC:
		case COMMAND_RED:
		case COMMAND_REDO:
		case COMMAND_DONE:
		case COMMAND_UNDONE:
		case COMMAND_EXIT:
			return true;
		default:
			return false;
		}
	}

	private static UserInput checkParameters(String commandWord, String input,
			UserInput ui) throws ParseException, InputEmptyException, InputInvalidException {
		switch (commandWord.toLowerCase()) {
		case COMMAND_ADD:
			return checkAddParameters(input, ui);
		case COMMAND_DELETE:
		case COMMAND_DEL:
			return checkDeleteParameters(input, ui);
		case COMMAND_DISPLAY:
		case COMMAND_DIS:
			return checkDisplayParameters(input, ui);
		case COMMAND_EDIT:
		case COMMAND_EDI:
			return checkEditParameters(input, ui);
		case COMMAND_SEARCH:
		case COMMAND_SRC:
			return checkSearchParameters(input, ui);
		case COMMAND_DONE:
			return checkDoneParameters(input, ui);
		case COMMAND_UNDONE:
			return checkUndoneParameters(input, ui);
		case COMMAND_UNDO:
		case COMMAND_UND:
		case COMMAND_REDO:
		case COMMAND_RED:
		case COMMAND_EXIT:
			return ui;
		default:
			assert false : commandWord;
		}
		return null;
	}

	private static UserInput checkDoneParameters(String input, UserInput ui) {
		if (isValidPositiveNumber(input.trim())) {
			ui.rowNumber = Integer.parseInt(input.trim());
		} else {
			assert !isValidPositiveNumber(input.trim()) : input;
			throw new InputMismatchException(ERROR_MESSAGE_DONE);
		}
		return ui;
	}

	private static UserInput checkUndoneParameters(String input, UserInput ui) {
		if (isValidPositiveNumber(input.trim())) {
			ui.rowNumber = Integer.parseInt(input.trim());
		} else {
			assert !isValidPositiveNumber(input.trim()) : input;
			throw new InputMismatchException(ERROR_MESSAGE_UNDONE);
		}
		return ui;
	}

	private static UserInput checkAddParameters(String input, UserInput ui)
			throws ParseException, InputEmptyException, InputInvalidException {
		if (input.trim().isEmpty()) {
			throw new InputEmptyException(ERROR_MESSAGE_NO_PARAMETERS);
		}
		String[] inputFragments = input.split(WHITESPACE);
		inputFragments = removeAllBlanks(inputFragments);
		int[] indexes = getIndexesOfEditTypes(inputFragments);
		ui = setAddParameters(ui, input, indexes, inputFragments);
		finalCheckOnAdd(ui);
		return ui;
	}

	private static void finalCheckOnAdd(UserInput ui) throws InputInvalidException {
		checkAddDates(ui);
		checkTimeWithoutDate(ui);
		checkTimeWithEndDateOnly(ui);
	}

	private static void checkTimeWithEndDateOnly(UserInput ui) throws InputInvalidException {
		SimpleDateFormat sdf = new SimpleDateFormat(STANDARDISED_TIME_FORMAT);
		final boolean inputHasEndDate = !ui.endD.isEmpty() && !ui.endD.equals(DASH);
		final boolean inputHasNoStartDate = ui.startD.isEmpty() || ui.startD.equals(DASH);
		if(inputHasEndDate && inputHasNoStartDate) {
			try {
				Date start = sdf.parse(ui.startT);
				Date end = sdf.parse(ui.endT);
				if(start.after(end)) {
					throw new InputInvalidException("Unable to Add: End time must be later than start time.");
				}
				if(start.equals(end)) {
					throw new InputInvalidException("Unable to Add: End time cannot be the same as start time.");
				}
			} catch(ParseException e) {
			}
		}
	}

	private static void checkTimeWithoutDate(UserInput ui) throws InputInvalidException {
		final boolean inputHasStartTime = !ui.startT.equals(DASH) && !ui.startT.isEmpty();
		final boolean inputHasEndTime = !ui.endT.equals(DASH) && !ui.endT.isEmpty();	
		final boolean inputHasTime = inputHasStartTime || inputHasEndTime;
		final boolean inputHasNoDate = ui.endD.equals(DASH) || ui.endD.isEmpty();
		if(inputHasNoDate) {
			if(inputHasTime) {
				throw new InputInvalidException("Unable to Add: Cannot have a time without a date.");
			}
		}
	}

	private static void checkAddDates(UserInput ui) throws InputInvalidException {
		SimpleDateFormat sdf = new SimpleDateFormat(STANDARDISED_DATE_FORMAT);
		final boolean inputHasNoEndDate = ui.endD.equals(DASH) || ui.endD.isEmpty();
		final boolean inputHasStartDate = !ui.startD.equals(DASH) || !ui.startD.isEmpty();
		if(inputHasNoEndDate && inputHasStartDate) {
				throw new InputInvalidException("Unable to Add: Cannot have start date without end date.");
		}
		try {
			Date start = sdf.parse(ui.startD);
			Date end = sdf.parse(ui.endD);
			if(start.after(end)) {
				throw new InputInvalidException("Unable to Add: End date must be later than start date.");
			}
			if(start.equals(end)) {
				throw new InputInvalidException("Unable to Add: End date cannot be the same as start date.");
			}
		}catch(ParseException e) {
		}
	}

	private static UserInput placeDateIntoUI(Date date, UserInput ui) {
		SimpleDateFormat outputDF = new SimpleDateFormat(
				STANDARDISED_DATE_FORMAT);
		if (ui.endD.isEmpty()) {
			ui.endD = outputDF.format(date);
		} else {
			assert !ui.endD.isEmpty() : ui.endD;
			try {
				if (outputDF.parse(ui.endD).before(date)) {
					ui.startD = ui.endD;
					ui.endD = outputDF.format(date);
				} else {
					assert !outputDF.parse(ui.endD).before(date) : ui.endD;
					ui.startD = outputDF.format(date);
				}
			} catch (ParseException e) {
			}
		}
		return ui;
	}

	private static UserInput checkDeleteParameters(String input, UserInput ui)
			throws InputEmptyException {
		if (input.trim().isEmpty()) {
			throw new InputEmptyException(ERROR_MESSAGE_NO_PARAMETERS);
		}
		if (isValidPositiveNumber(input.trim())) {
			ui.rowNumber = Integer.parseInt(input.trim());
		} else {
			throw new InputMismatchException(ERROR_MESSAGE_DELETE);
		}
		return ui;
	}

	private static boolean isValidPositiveNumber(String input) {
		int i = 0;
		try {
			i = Integer.parseInt(input);
		} catch (NumberFormatException e) {
		}
		return i > 0;
	}

	private static UserInput checkDisplayParameters(String input, UserInput ui)
			throws ParseException, InputEmptyException {
		if (input.trim().isEmpty()) {
			throw new InputEmptyException(ERROR_MESSAGE_NO_PARAMETERS);
		}
		String[] fragments = input.split(WHITESPACE);
		fragments = removeAllBlanks(fragments);
		ui.displayType = fragments[DISPLAY_TYPE].toLowerCase();
		switch (ui.displayType) {
		case DISPLAY_ALL_FLOATING:
		case DISPLAY_ALL:
			break;
		case DISPLAY_RANGE:
			if (fragments.length != 3) {
				throw new InputMismatchException(ERROR_MESSAGE_DISPLAY_RANGE);
			}
			Date firstDate = parseDate(fragments[FIRST_DATE]);
			Date secondDate = parseDate(fragments[SECOND_DATE]);
			ui = placeDateIntoUI(firstDate, ui);
			ui = placeDateIntoUI(secondDate, ui);
			break;
		default:
			throw new InputMismatchException(ERROR_MESSAGE_DISPLAY);
		}
		return ui;
	}

	private static UserInput checkSearchParameters(String input, UserInput ui)
			throws InputEmptyException {
		if (input.trim().isEmpty()) {
			throw new InputEmptyException(ERROR_MESSAGE_NO_PARAMETERS);
		}
		ui.keyword = input.trim();
		return ui;
	}

	private static UserInput checkEditParameters(String input, UserInput ui)
			throws ParseException, InputEmptyException, InputInvalidException {
		if (input.trim().isEmpty()) {
			throw new InputEmptyException(ERROR_MESSAGE_NO_PARAMETERS);
		}
		String[] fragments = input.split(WHITESPACE);
		fragments = removeAllBlanks(fragments);
		if (isValidPositiveNumber(fragments[EDIT_ROW])) {
			ui.rowNumber = Integer.parseInt(fragments[EDIT_ROW]);
		} else {
			throw new InputMismatchException(ERROR_MESSAGE_EDIT_INVALID_ROW);
		}
		if (fragments.length == 1) {
			throw new InputMismatchException(ERROR_MESSAGE_EDIT_NO_PARAMETERS);
		}
		int[] indexes = getIndexesOfEditTypes(fragments);
		ui = setEditParameters(ui, input, indexes, fragments);
		return ui;
	}

	private static UserInput setAddParameters(UserInput ui, String input,
			int[] indexes, String[] fragments) throws ParseException {
		for (int index = FIRST_INDEX; index < indexes.length; index++) {
			if (indexes[index] != INDEX_NOT_FOUND) {
				ui = setAddOrEditParameter(ui, index, indexes[index], fragments);
			}
		}
		if (input.contains(TASK_START_INDICATOR)
				&& input.contains(TASK_END_INDICATOR)) {
			ui.task = input.substring(input.indexOf(TASK_START_INDICATOR) + 1,
					input.lastIndexOf(TASK_END_INDICATOR));
		} else {
			throw new InputMismatchException("Task must be marked by <>.");
		}
		return ui;
	}

	private static UserInput setEditParameters(UserInput ui, String input,
			int[] indexes, String[] fragments) throws ParseException {
		for (int index = FIRST_INDEX; index < indexes.length; index++) {
			if (indexes[index] != INDEX_NOT_FOUND) {
				ui = setAddOrEditParameter(ui, index, indexes[index], fragments);
			}
		}
		if (input.contains(TASK_START_INDICATOR)) {
			if (input.contains(TASK_END_INDICATOR)) {
				ui.task = input.substring(
						input.indexOf(TASK_START_INDICATOR) + 1,
						input.lastIndexOf(TASK_END_INDICATOR));
			} else {
				throw new InputMismatchException("Task must be marked by <>.");
			}
		}
		return ui;
	}

	private static UserInput setAddOrEditParameter(UserInput ui, int index,
			int i, String[] fragments) throws ParseException {
		switch (index) {
		case INDEX_START_DATE:
			ui = setStartDate(ui, i, fragments);
			break;
		case INDEX_END_DATE:
			ui = setEndDate(ui, i, fragments);
			break;
		case INDEX_BOTH_DATE:
			ui = setBothDate(ui, i, fragments);
			break;
		case INDEX_START_TIME:
			ui = setStartTime(ui, i, fragments);
			break;
		case INDEX_END_TIME:
			ui = setEndTime(ui, i, fragments);
			break;
		case INDEX_BOTH_TIME:
			ui = setBothTime(ui, i, fragments);
			break;
		}
		return ui;
	}

	private static UserInput setStartDate(UserInput ui, int i,
			String[] fragments) throws ParseException {
		SimpleDateFormat dateFormatter = new SimpleDateFormat(
				STANDARDISED_DATE_FORMAT);
		try {
			Date startDate = parseDate(fragments[i + OFFSET_FOR_SD_ST_ED_ET]);
			ui.startD = dateFormatter.format(startDate);
		} catch (ArrayIndexOutOfBoundsException e) {
			throw new InputMismatchException(ERROR_MESSAGE_NO_SD);
		} catch (ParseException pe) {
			if (fragments[i + OFFSET_FOR_SD_ST_ED_ET].equals(DASH)) {
				ui.startD = DASH;
			} else {
				throw new ParseException(ERROR_MESSAGE_WRONG_SD, 2);
			}
		}
		return ui;
	}

	private static UserInput setEndDate(UserInput ui, int i, String[] fragments)
			throws ParseException {
		SimpleDateFormat dateFormatter = new SimpleDateFormat(
				STANDARDISED_DATE_FORMAT);
		try {
			Date endDate = parseDate(fragments[i + OFFSET_FOR_SD_ST_ED_ET]);
			ui.endD = dateFormatter.format(endDate);
		} catch (ArrayIndexOutOfBoundsException e) {
			throw new InputMismatchException(ERROR_MESSAGE_NO_ED);
		} catch (ParseException pe) {
			if (fragments[i + OFFSET_FOR_SD_ST_ED_ET].equals(DASH)) {
				ui.endD = DASH;
			} else {
				throw new ParseException(ERROR_MESSAGE_WRONG_ED, 2);
			}
		}
		return ui;
	}

	private static UserInput setBothDate(UserInput ui, int i, String[] fragments)
			throws ParseException {
		SimpleDateFormat dateFormatter = new SimpleDateFormat(
				STANDARDISED_DATE_FORMAT);
		try {
			Date startDate = parseDate(fragments[i + OFFSET_FOR_SD_ST_ED_ET]);
			ui.startD = dateFormatter.format(startDate);
		} catch (ArrayIndexOutOfBoundsException e) {
			throw new InputMismatchException(ERROR_MESSAGE_NO_SD);
		} catch (ParseException pe) {
			if (fragments[i + OFFSET_FOR_SD_ST_ED_ET].equals(DASH)) {
				ui.startD = DASH;
			} else {
				throw new ParseException(ERROR_MESSAGE_WRONG_SD, 2);
			}
		}
		try {
			Date endDate = parseDate(fragments[i + OFFSET_FOR_BD_BT]);
			ui.endD = dateFormatter.format(endDate);
		} catch (ArrayIndexOutOfBoundsException e) {
			throw new InputMismatchException(ERROR_MESSAGE_NO_ED);
		} catch (ParseException pe) {
			if (fragments[i + OFFSET_FOR_BD_BT].equals(DASH)) {
				ui.endD = DASH;
			} else {
				throw new ParseException(ERROR_MESSAGE_WRONG_ED, 2);
			}
		}
		return ui;
	}

	private static UserInput setStartTime(UserInput ui, int i,
			String[] fragments) throws ParseException {
		SimpleDateFormat timeFormatter = new SimpleDateFormat(
				STANDARDISED_TIME_FORMAT);
		try {
			Date startTime = parseTime(fragments[i + OFFSET_FOR_SD_ST_ED_ET]);
			ui.startT = timeFormatter.format(startTime);
		} catch (ArrayIndexOutOfBoundsException e) {
			throw new InputMismatchException(ERROR_MESSAGE_NO_ST);
		} catch (ParseException pe) {
			if (fragments[i + OFFSET_FOR_SD_ST_ED_ET].equals(DASH)) {
				ui.startT = DASH;
			} else {
				throw new ParseException(ERROR_MESSAGE_WRONG_ST, 2);
			}
		}
		return ui;
	}

	private static UserInput setEndTime(UserInput ui, int i, String[] fragments)
			throws ParseException {
		SimpleDateFormat timeFormatter = new SimpleDateFormat(
				STANDARDISED_TIME_FORMAT);
		try {
			Date endTime = parseTime(fragments[i + OFFSET_FOR_SD_ST_ED_ET]);
			ui.endT = timeFormatter.format(endTime);
		} catch (ArrayIndexOutOfBoundsException e) {
			throw new InputMismatchException(ERROR_MESSAGE_NO_ET);
		} catch (ParseException pe) {
			if (fragments[i + OFFSET_FOR_SD_ST_ED_ET].equals(DASH)) {
				ui.endT = DASH;
			} else {
				throw new ParseException(ERROR_MESSAGE_WRONG_ET, 2);
			}
		}
		return ui;
	}

	private static UserInput setBothTime(UserInput ui, int i, String[] fragments)
			throws ParseException {
		SimpleDateFormat timeFormatter = new SimpleDateFormat(
				STANDARDISED_TIME_FORMAT);
		try {
			Date startTime = parseTime(fragments[i + OFFSET_FOR_SD_ST_ED_ET]);
			ui.startT = timeFormatter.format(startTime);
		} catch (ArrayIndexOutOfBoundsException e) {
			throw new InputMismatchException(ERROR_MESSAGE_NO_ST);
		} catch (ParseException pe) {
			if (fragments[i + OFFSET_FOR_SD_ST_ED_ET].equals(DASH)) {
				ui.startT = DASH;
			} else {
				throw new ParseException(ERROR_MESSAGE_WRONG_ST, 2);
			}
		}
		try {
			Date endTime = parseDate(fragments[i + OFFSET_FOR_BD_BT]);
			ui.endT = timeFormatter.format(endTime);
		} catch (ArrayIndexOutOfBoundsException e) {
			throw new InputMismatchException(ERROR_MESSAGE_NO_ET);
		} catch (ParseException pe) {
			if (fragments[i + OFFSET_FOR_BD_BT].equals(DASH)) {
				ui.endT = DASH;
			} else {
				throw new ParseException(ERROR_MESSAGE_WRONG_ET, 2);
			}
		}
		return ui;
	}

	private static int[] getIndexesOfEditTypes(String[] fragments) {
		int indexOfST = INDEX_NOT_FOUND, indexOfET = INDEX_NOT_FOUND, indexOfBT = INDEX_NOT_FOUND, indexOfSD = INDEX_NOT_FOUND, indexOfED = INDEX_NOT_FOUND, indexOfBD = INDEX_NOT_FOUND;
		for (int index = 0; index < fragments.length; index++) {
			switch (fragments[index].toLowerCase()) {
			case SHORTFORM_START_TIME:
				indexOfST = index;
				break;
			case SHORTFORM_END_TIME:
				indexOfET = index;
				break;
			case SHORTFORM_BOTH_TIME:
				indexOfBT = index;
				break;
			case SHORTFORM_START_DATE:
				indexOfSD = index;
				break;
			case SHORTFORM_END_DATE:
				indexOfED = index;
				break;
			case SHORTFORM_BOTH_DATE:
				indexOfBD = index;
				break;
			}
		}
		return new int[] { indexOfSD, indexOfED, indexOfBD, indexOfST,
				indexOfET, indexOfBT };
	}

	private static String[] removeAllBlanks(String[] fragments) {
		Vector<String> nonBlanks = new Vector<String>();
		int i = START_INDEX;
		for (String s : fragments) {
			if (!s.trim().equals(EMPTY_STRING)) {
				nonBlanks.add(s);
			}
		}
		String[] output = new String[nonBlanks.size()];
		for (String s : nonBlanks) {
			output[i++] = s;
		}
		return output;
	}

	private static Date parseDate(String fragment) throws ParseException {
		boolean fragmentIsDate = false;
		String[] dateFormats = new String[] { "dd/M/yyyy", "dd/M/yy",
				"dd/MM/yyyy", STANDARDISED_DATE_FORMAT, "d/M/yyyy", "d/M/yy",
				"d/MM/yyyy", "d/MM/yy", "dd-M-yyyy", "dd-M-yy", "dd-MM-yyyy",
				"dd-MM-yy", "d-M-yyyy", "d-M-yy", "d-MM-yyyy", "d-MM-yy",
				"dd.M.yyyy", "dd.M.yy", "dd.MM.yyyy", "dd.MM.yy", "d.M.yyyy",
				"d.M.yy", "d.MM.yyyy", "d.MM.yy" };
		Date testDate = null;
		for (String format : dateFormats) {
			if (!fragmentIsDate) {
				SimpleDateFormat sdf = new SimpleDateFormat(format);
				try {
					testDate = sdf.parse(fragment);
				} catch (ParseException e) {
				}
				if (testDate != null) {
					fragmentIsDate = true;
					if (!sdf.format(testDate).equals(fragment)) {
						fragmentIsDate = false;
					}
				}
			}
		}
		if (fragmentIsDate) {
			return testDate;
		} else {
			throw new ParseException("Parameter is not a date.", 0);
		}
	}

	private static Date parseTime(String fragment) throws ParseException {
		fragment = fragment.toUpperCase();
		boolean fragmentIsTime = false;
		String[] timeFormats = new String[] { STANDARDISED_TIME_FORMAT,
				"HH.mm", "HH:mm", "h:mma", "h.mma", "ha", "hha" };
		Date testTime = null;
		for (String format : timeFormats) {
			if (!fragmentIsTime) {
				SimpleDateFormat sdf = new SimpleDateFormat(format);
				try {
					testTime = sdf.parse(fragment);
				} catch (ParseException e) {
				}
				if (testTime != null) {
					fragmentIsTime = true;
					if (!sdf.format(testTime).equals(fragment)) {
						fragmentIsTime = false;
					}
				}
			}
		}
		if (fragmentIsTime) {
			return testTime;
		} else {
			throw new ParseException("Parameter is not a time.", 1);
		}
	}

	public static String outputAddParameters(String input) {
		UserInput test = new UserInput();
		try {
			test = checkAddParameters(input, test);
		} catch (ParseException | InputEmptyException | InputInvalidException iee) {
			return iee.getMessage();
		}
		String output = "";
		if (!test.startD.isEmpty()) {
			output += test.startD + WHITESPACE;
		}
		if (!test.startT.isEmpty()) {
			output += test.startT + WHITESPACE;
		}
		if (!test.endD.isEmpty()) {
			output += test.endD + WHITESPACE;
		}
		if (!test.endT.isEmpty()) {
			output += test.endT + WHITESPACE;
		}
		output += test.task;
		return output;
	}

	public static String outputDeleteParameters(String input) {
		UserInput test = new UserInput();
		try {
			test = checkDeleteParameters(input, test);
		} catch (InputEmptyException iee) {
			return iee.getMessage();
		}
		String output = "";
		output += test.rowNumber;
		output += WHITESPACE + test.validity;
		output += WHITESPACE + test.message;
		return output.trim();
	}

	public static String outputDisplayParamters(String input) {
		UserInput test = new UserInput();
		try {
			test = checkDisplayParameters(input, test);
		} catch (ParseException | InputEmptyException iee) {
			return iee.getMessage();
		}
		String output = "";
		output += test.displayType;
		if (!test.startD.isEmpty()) {
			output += WHITESPACE + test.startD;
		}
		if (!test.startT.isEmpty()) {
			output += test.startT + WHITESPACE;
		}
		if (!test.endD.isEmpty()) {
			output += WHITESPACE + test.endD;
		}
		output += WHITESPACE + test.validity;
		output += WHITESPACE + test.message;
		return output.trim();
	}

	public static String outputEditParamters(String input) {
		UserInput test = new UserInput();
		try {
			test = checkEditParameters(input, test);
		} catch (ParseException | InputEmptyException | InputInvalidException iee) {
			return iee.getMessage();
		}
		String output = "";
		output += test.rowNumber + WHITESPACE;
		if (!test.startD.isEmpty()) {
			output += test.startD + WHITESPACE;
		}
		if (!test.startT.isEmpty()) {
			output += test.startT + WHITESPACE;
		}
		if (!test.endD.isEmpty()) {
			output += test.endD + WHITESPACE;
		}
		if (!test.endT.isEmpty()) {
			output += test.endT + WHITESPACE;
		}
		if (!test.task.isEmpty()) {
			output += test.task + WHITESPACE;
		}
		output += WHITESPACE + test.validity;
		output += WHITESPACE + test.message;
		return output.trim();
	}

	public static String testPlaceDateIntoUI(String input) {
		UserInput test = new UserInput();
		Date date = null;
		try {
			date = parseDate(input);
		} catch (ParseException e) {
			return e.getMessage();
		}
		test = placeDateIntoUI(date, test);
		return test.endD;
	}

	public static boolean testIsCommandWord(String string) {
		return isCommandWord(string);
	}
}
